package com.example.dingtalk.service.impl;

import com.aliyun.dingtalkworkflow_1_0.Client;
import com.aliyun.dingtalkworkflow_1_0.models.*;
import com.aliyun.tea.TeaException;
import com.aliyun.teautil.models.RuntimeOptions;
import com.example.dingtalk.entity.Approve;
import com.example.dingtalk.entity.Form;
import com.example.dingtalk.entity.User;
import com.example.dingtalk.service.OaService;
import com.example.dingtalk.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @Description :
 * @Author : Bruce Lee
 * @CreateTime : 2024/5/23
 */

@Slf4j
@Service
public class OaServiceImpl implements OaService {

//    @Value("${dingtalk.accessToken}")
//    private String accessKeyId;

    @Value("${dingtalk.appKey}")
    private String appKey;

    @Value("${dingtalk.appSecret}")
    private String accessKeySecret;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 创建钉钉客户端
     * @return
     * @throws Exception
     */
    public static com.aliyun.dingtalkworkflow_1_0.Client createClient() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkworkflow_1_0.Client(config);
    }


    /**
     * 提交审批
     * @throws Exception
     */
    public void commitApprove(User user, Form form) throws Exception {
        Client client = createClient();
        com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceHeaders startProcessInstanceHeaders = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceHeaders();
        startProcessInstanceHeaders.xAcsDingtalkAccessToken = getAccessTokenFromRedis();
        com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues formComponentValues0 = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
                .setName(form.getNameFirst())
                .setValue(form.getValueFirst());
        // 添加审批人
        com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestApprovers approvers = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestApprovers()
                .setUserIds(java.util.Arrays.asList(
                        user.getUserId()
                ));

        com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest startProcessInstanceRequest = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest()
                .setDeptId(user.getDeptId())
                .setApprovers(java.util.Arrays.asList(
                        approvers
                ))
                .setOriginatorUserId(user.getUserId())
                .setProcessCode("PROC-3915C166-DD31-422F-935D-58C1ACC14F7F")
                .setFormComponentValues(java.util.Arrays.asList(
                        formComponentValues0
                ));
        try {
            StartProcessInstanceResponse startProcessInstanceResponse = client.startProcessInstanceWithOptions(startProcessInstanceRequest, startProcessInstanceHeaders, new RuntimeOptions());
            log.info("审批示例ID：" + startProcessInstanceResponse.getBody().getInstanceId());
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }

        } catch (Exception _err) {
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }

        }
    }

    /**
     * 获取审批实例信息
     * @throws Exception
     */

    public GetProcessInstanceResponse getProcessInstance(String processInstanceId) throws Exception {
        Client client = createClient();
        com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceHeaders getProcessInstanceHeaders = new com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceHeaders();
        getProcessInstanceHeaders.xAcsDingtalkAccessToken = getAccessTokenFromRedis();
        com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceRequest getProcessInstanceRequest = new com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceRequest()
                .setProcessInstanceId(processInstanceId);
        try {
            GetProcessInstanceResponse instanceWithOptions = client.getProcessInstanceWithOptions(getProcessInstanceRequest, getProcessInstanceHeaders, new RuntimeOptions());
//            log.info("审批实例信息：" + instanceWithOptions.getBody().getResult().getTasks());
            return instanceWithOptions;
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }

        } catch (Exception _err) {
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }

        }
        return null;

    }


    /**
     * 执行审批操作, 并添加审批意见
     */
    public void executeProcessInstance(Approve approve) throws Exception {
        Client client = createClient();
        com.aliyun.dingtalkworkflow_1_0.models.ExecuteProcessInstanceHeaders executeProcessInstanceHeaders = new com.aliyun.dingtalkworkflow_1_0.models.ExecuteProcessInstanceHeaders();
        executeProcessInstanceHeaders.xAcsDingtalkAccessToken = getAccessTokenFromRedis();
        com.aliyun.dingtalkworkflow_1_0.models.ExecuteProcessInstanceRequest executeProcessInstanceRequest = new com.aliyun.dingtalkworkflow_1_0.models.ExecuteProcessInstanceRequest()
                .setResult(approve.getResult())
                .setProcessInstanceId(approve.getProcessInstanceId())
                // 填写任务taskId
                .setTaskId(approve.getTaskId())
                .setActionerUserId(approve.getUserId());
        try {
            client.executeProcessInstanceWithOptions(executeProcessInstanceRequest, executeProcessInstanceHeaders, new com.aliyun.teautil.models.RuntimeOptions());
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }

        } catch (Exception _err) {
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }
        }
        if (!com.aliyun.teautil.Common.empty(approve.getComment())){
            com.aliyun.dingtalkworkflow_1_0.models.AddProcessInstanceCommentHeaders addProcessInstanceCommentHeaders = new com.aliyun.dingtalkworkflow_1_0.models.AddProcessInstanceCommentHeaders();
            addProcessInstanceCommentHeaders.xAcsDingtalkAccessToken = getAccessTokenFromRedis();
            com.aliyun.dingtalkworkflow_1_0.models.AddProcessInstanceCommentRequest addProcessInstanceCommentRequest = new com.aliyun.dingtalkworkflow_1_0.models.AddProcessInstanceCommentRequest()
                    .setProcessInstanceId(approve.getProcessInstanceId())
                    .setCommentUserId(approve.getUserId())
                    .setText(approve.getComment());
            try {
                client.addProcessInstanceCommentWithOptions(addProcessInstanceCommentRequest, addProcessInstanceCommentHeaders, new com.aliyun.teautil.models.RuntimeOptions());
            }catch (TeaException err) {
                if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                    // err 中含有 code 和 message 属性，可帮助开发定位问题
                }
            } catch (Exception _err) {
                TeaException err = new TeaException(_err.getMessage(), _err);
                if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                    // err 中含有 code 和 message 属性，可帮助开发定位问题
                }
            }
        }
    }

    /**
     * 获取用户待办审批流数量
     */
    public void getProcessList() throws Exception {
        Client client = createClient();
        com.aliyun.dingtalkworkflow_1_0.models.GetUserTodoTaskSumHeaders getUserTodoTaskSumHeaders = new com.aliyun.dingtalkworkflow_1_0.models.GetUserTodoTaskSumHeaders();
        getUserTodoTaskSumHeaders.xAcsDingtalkAccessToken = getAccessTokenFromRedis();
        com.aliyun.dingtalkworkflow_1_0.models.GetUserTodoTaskSumRequest getUserTodoTaskSumRequest = new com.aliyun.dingtalkworkflow_1_0.models.GetUserTodoTaskSumRequest().setUserId("manager6924");

        try {
            GetUserTodoTaskSumResponse userTodoTaskSumWithOptions = client.getUserTodoTaskSumWithOptions(getUserTodoTaskSumRequest, getUserTodoTaskSumHeaders, new RuntimeOptions());
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
                log.info("审批流列表：" + err.message);
            }

        } catch (Exception _err) {
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
                log.info("审批流列表：" + err.message);
            }

        }
    }

    /**
     * 获取所有待办审批流ID列表
     */
    public ListProcessInstanceIdsResponseBody.ListProcessInstanceIdsResponseBodyResult getProcessListByPage(Long startTime, String processCode, Long nextToken, Long maxResults, String statuses) throws Exception {
        Client client = createClient();
        com.aliyun.dingtalkworkflow_1_0.models.ListProcessInstanceIdsHeaders listProcessInstanceIdsHeaders = new com.aliyun.dingtalkworkflow_1_0.models.ListProcessInstanceIdsHeaders();
        listProcessInstanceIdsHeaders.xAcsDingtalkAccessToken = getAccessTokenFromRedis();
        com.aliyun.dingtalkworkflow_1_0.models.ListProcessInstanceIdsRequest listProcessInstanceIdsRequest = new com.aliyun.dingtalkworkflow_1_0.models.ListProcessInstanceIdsRequest()
                .setStatuses(java.util.Arrays.asList(
//                        "RUNNING"
                        statuses
                ))
                .setStartTime(startTime)
                .setProcessCode(processCode)
                .setNextToken(nextToken)
                .setMaxResults(maxResults);
        try {
            ListProcessInstanceIdsResponse listProcessInstanceIdsResponse = client.listProcessInstanceIdsWithOptions(listProcessInstanceIdsRequest, listProcessInstanceIdsHeaders, new RuntimeOptions());
            return listProcessInstanceIdsResponse.getBody().getResult();
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }

        } catch (Exception _err) {
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }

        }
        return null;
    }

    /**
     * 获取钉钉API的accessToken
     * @return
     */
    @Override
    public String getAccessToken() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        com.aliyun.dingtalkoauth2_1_0.Client client = new com.aliyun.dingtalkoauth2_1_0.Client(config);
        com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest getAccessTokenRequest = new com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest()
                .setAppKey(appKey)
                .setAppSecret(accessKeySecret);
        try {
            return client.getAccessToken(getAccessTokenRequest).getBody().getAccessToken();
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }
        } catch (Exception _err) {
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 message 属性，可帮助开发定位问题
            }
        }
        return null;
    }

    /**
     * 从redis中获取钉钉API的accessToken, 避免频繁调用钉钉接口
     */
    public String getAccessTokenFromRedis() {
        String accessToken = redisUtil.getCacheObject("accessToken");
        if (accessToken != null){
            return accessToken;
        }else {
            try {
                accessToken = getAccessToken();
                // 钉钉官方文档中accessToken的有效期为2小时
                redisUtil.setCacheObject("accessToken",accessToken, 59*60*2, TimeUnit.SECONDS);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return accessToken;
        }
    }
}
